package it.blueocean.acanto.taglibrary.jsp.taglib.tags.dataset;

import it.blueocean.acanto.taglibrary.jsp.taglib.tags.dataset.filter.DatasetFilter;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

import javax.inject.Inject;
import javax.inject.Named;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;

@Named("JDBCDataset")
@Scope(BeanDefinition.SCOPE_SINGLETON)
public class JDBCDataset extends DataSetStateBean
{
	private static final long serialVersionUID = 45641233743598L;

	private final static Logger logger_ = LoggerFactory.getLogger(JDBCDataset.class);
	
	@Inject
	@Named("dataSource")
	private DataSource dataSource;

	public JDBCDataset()
	{
	}

	protected QueryExecutionResult executeQuery(int i, int j) throws SQLException, NamingException
	{
		Connection connection = dataSource.getConnection();
		String s = getCompleteQuery();
		logger_.debug(s);
		PreparedStatement preparedstatement = connection.prepareStatement(s);
		Iterator iterator = getParams().iterator();
		int k;
		for (k = 1; iterator.hasNext(); k++)
		{
			Object obj1 = iterator.next();
			logger_.debug((new StringBuilder()).append("setting param ").append(k).append(": '").append(obj1)
					.append("'").toString());
			setParam(preparedstatement, k, obj1);
		}

		DatasetFilter datasetfilter = getDatasetFilter();
		if(datasetfilter != null && datasetfilter.getFilterString().length() > 0)
		{
			for (Iterator iterator1 = datasetfilter.getFilterParams().iterator(); iterator1.hasNext();)
			{
				Object obj2 = iterator1.next();
				logger_.debug((new StringBuilder()).append("setting filter param ").append(k).append(": '")
						.append(obj2).append("'").toString());
				setParam(preparedstatement, k, obj2);
				k++;
			}

		}
		ResultSet resultset = preparedstatement.executeQuery();
		String s1 = (new StringBuilder()).append("select count(*) as countRows from (").append(getQuery())
				.append(") countTable").toString();
		if(datasetfilter != null && datasetfilter.getFilterString().length() > 0)
			s1 = (new StringBuilder()).append(s1).append(" where ").append(datasetfilter.getFilterString()).toString();
		PreparedStatement preparedstatement1 = connection.prepareStatement(s1);
		iterator = getParams().iterator();
		for (k = 1; iterator.hasNext(); k++)
		{
			Object obj3 = iterator.next();
			logger_.debug((new StringBuilder()).append("setting param ").append(k).append(": '").append(obj3)
					.append("'").toString());
			setParam(preparedstatement1, k, obj3);
		}

		if(datasetfilter != null && datasetfilter.getFilterString().length() > 0)
		{
			for (Iterator iterator2 = datasetfilter.getFilterParams().iterator(); iterator2.hasNext();)
			{
				Object obj4 = iterator2.next();
				logger_.debug((new StringBuilder()).append("setting filter param ").append(k).append(": '")
						.append(obj4).append("'").toString());
				setParam(preparedstatement1, k, obj4);
				k++;
			}

		}
		ResultSet resultset1 = preparedstatement1.executeQuery();
		if(!resultset1.next())
			throw new SQLException((new StringBuilder()).append("Query ").append(getQuery())
					.append(" returned no result").toString());
		int l = resultset1.getInt("countRows");
		ResultSetMetaData resultsetmetadata = resultset.getMetaData();
		String as[] = new String[resultsetmetadata.getColumnCount()];
		for (int i1 = 0; i1 < as.length; i1++)
			as[i1] = resultsetmetadata.getColumnName(i1 + 1);
		for (int j1 = 0; j1 < i; j1++)
			resultset.next();
		if(i > l)
			i = l;
		int k1 = j <= 0 ? l - i : Math.min(j, l - i);
		Map amap[] = new Map[k1];
		for (int l1 = 0; l1 < amap.length && resultset.next(); l1++)
		{
			TreeMap treemap = new TreeMap(String.CASE_INSENSITIVE_ORDER);
			for (int i2 = 0; i2 < as.length; i2++)
			{
				int j2 = resultsetmetadata.getColumnType(i2 + 1);
				if(j2 == 91 || j2 == 93 || j2 == 92)
				{
					Timestamp timestamp = resultset.getTimestamp(i2 + 1);
					if(timestamp != null)
						treemap.put(as[i2], new Date(timestamp.getTime()));
					else
						treemap.put(as[i2], null);
				}
				else
				{
					treemap.put(as[i2], resultset.getObject(i2 + 1));
				}
			}

			amap[l1] = treemap;
		}

		resultset.close();
		preparedstatement.close();
		resultset1.close();
		preparedstatement1.close();
		return new QueryExecutionResult(as, amap, l);
	}

	private void setParam(PreparedStatement preparedstatement, int i, Object obj) throws SQLException
	{
		if(obj instanceof Date)
		{
			Date date = (Date) obj;
			preparedstatement.setTimestamp(i, new Timestamp(date.getTime()));
		}
		else
		if(obj instanceof Integer)
		{
			Integer integer = (Integer) obj;
			preparedstatement.setInt(i, integer.intValue());
		}
		else
		if(obj instanceof Double)
		{
			Double double1 = (Double) obj;
			preparedstatement.setDouble(i, double1.doubleValue());
		}
		else
		if(obj instanceof Float)
		{
			Float float1 = (Float) obj;
			preparedstatement.setFloat(i, float1.floatValue());
		}
		else
		if(obj instanceof Long)
		{
			Long long1 = (Long) obj;
			preparedstatement.setLong(i, long1.longValue());
		}
		else
		if(obj instanceof Boolean)
		{
			Boolean boolean1 = (Boolean) obj;
			preparedstatement.setBoolean(i, boolean1.booleanValue());
		}
		else
		{
			preparedstatement.setString(i, obj.toString());
		}
	}

	public String getCompleteQuery()
	{
		String s = getQuery();
		DatasetFilter datasetfilter = getDatasetFilter();
		OrderByClause orderbyclause = getOrderByClause();
		if(datasetfilter != null && datasetfilter.getFilterString().length() > 0 || orderbyclause != null)
		{
			s = (new StringBuilder()).append("select * from (").append(s).append(") completeQueryTable").toString();
			if(datasetfilter != null && datasetfilter.getFilterString().length() > 0)
				s = (new StringBuilder()).append(s).append(" where ").append(datasetfilter.getFilterString())
						.toString();
			if(orderbyclause != null)
				s = (new StringBuilder()).append(s).append(" order by ").append(orderbyclause).toString();
		}
		return s;
	}

}
